from ConstrainPropagation import CSP
from Constraint import Constraint
from Preferences import Prefenerce
from typing import Dict, List, Optional


class ProduceConstraint(Constraint[List[float], List[float]]):

    def __init__(self, A, B) -> None:
        variables: List[int] = [v for v in range(0, len(B))]
        super().__init__(variables)
        self.A = A
        self.B = B

    def satisfied(self, assignment: Dict[int, int]) -> bool:

        for index in range(0, len(self.A)):
            sum = 0
            for variable, value in assignment.items():
                if value == index:
                    sum = sum + self.B[variable]
            if sum >= self.A[index]:
                return False
        return True

class ProducePreference(Prefenerce):
    def __init__(self, A, B) -> None:
        variables: List[int] = [v for v in range(0, len(B))]
        super().__init__(variables)
        self.A = A
        self.B = B

    def preferences(self, old_assignment: Dict[int, int], new_assignment: Dict[int, int]) -> bool:
        if not bool(old_assignment):
            return True

        old_sum = 0
        new_sum = 0
        old_templist = []
        new_templist = []
        for variable, value in old_assignment.items():
            if value not in old_templist:
                old_templist.append(value)
        for value in old_templist:
            old_sum = old_sum + self.A[value]

        for variable, value in new_assignment.items():
            if value not in new_templist:
                new_templist.append(value)
        for value in new_templist:
            new_sum = new_sum + self.A[value]

        if old_sum > new_sum:
            return True
        return False


if __name__ == '__main__':
    A: List[float] = []
    B: List[float] = []
    while 1:
        choice = input(f"请选择测试方法（hint：A为手动输入，B为从测试文件读取测试用例，Q为退出）：")
        if choice == "A":
            problemtype = input(f"请确定问题类型（hint：csp为约束满足问题，cop为约束优化问题）：")
            len_A = input(f"请输入工料数量：")
            line = input(f"请输入每个工料的长短：")
            A = list(map(float, line.strip().replace(" ", "").split(",")))
            len_B = input(f"请输入部件数量：")
            line = input(f"请输入每个部件需要的工料长度：")
            B = list(map(float, line.strip().replace(" ", "").split(",")))
        elif choice == "B":
            problemtype = input(f"请确定问题类型（hint：csp为约束满足问题，cop为约束优化问题）：")
            filename = input(f"请输入测试文件名（应放置在Test文件夹下）：")
            with open(f"./Test/{filename}", "r") as f:
                numberline: int = 0
                for line in f:
                    numberline = numberline + 1
                    if numberline == 2:
                        A = list(map(float, line.strip().replace(" ", "").split(",")))
                    elif numberline == 4:
                        B = list(map(float, line.strip().replace(" ", "").split(",")))
        elif choice == "Q":
            print("Thanks for using.")
            break
        else:
            raise LookupError("Input Error")

        variables: List[int] = [v for v in range(0, len(B))]
        domains: Dict[int, List[int]] = {}

        for variable in variables:
            domains[variable] = list(range(0, len(A)))

        csp: CSP[int, int] = CSP(variables, domains, problemtype, ProducePreference(A, B))
        csp.add_constraint(ProduceConstraint(A, B))

        solution: Optional[Dict[int, int]] = {}
        if problemtype == "csp":
            solution: Optional[Dict[int, int]] = csp.backtracking_search()
        elif problemtype == "cop":
            csp.backtracking_search()
            solution: Optional[Dict[int, int]] = csp.assignment

        if solution is None:
            print("No solution found!")
        else:
            print(f"solution:{solution}")
